package com.wmh.baseservice.robot.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.job.CronUtils;
import com.wmh.baseservice.common.job.quartz.SchedulerManager;
import com.wmh.baseservice.common.mybatisplus.structure.LambdaQueryWrapperX;
import com.wmh.baseservice.common.utils.web.UserUtil;
import com.wmh.baseservice.robot.convert.RobotJobTaskConvert;
import com.wmh.baseservice.robot.entity.RobotJobTask;
import com.wmh.baseservice.robot.enums.RobotJobTaskStatus;
import com.wmh.baseservice.robot.job.TaskJobHandler;
import com.wmh.baseservice.robot.mapper.RobotJobTaskMapper;
import com.wmh.baseservice.robot.pojo.vo.robotjobtask.RobotJobTaskAddReqVO;
import com.wmh.baseservice.robot.pojo.vo.robotjobtask.RobotJobTaskUpdateReqVO;
import com.wmh.baseservice.robot.service.RobotJobTaskService;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;

import static com.wmh.baseservice.robot.enums.RobotJobTaskStatus.OPENING;
import static com.wmh.baseservice.robot.enums.RobotJobTaskStatus.PAUSING;

/**
 * @author 谢骏
 * @description 针对表【robot_job_task】的数据库操作Service实现
 * @createDate 2023-08-31 14:51:17
 */
@Service
public class RobotJobTaskServiceImpl extends ServiceImpl<RobotJobTaskMapper, RobotJobTask>
        implements RobotJobTaskService {

    @Resource
    private UserUtil userUtil;

    @Resource
    private SchedulerManager schedulerManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(RobotJobTaskAddReqVO reqVO) throws SchedulerException {
        checkCron(reqVO.getCron());
        checkNameUnique(null, reqVO.getName());
        RobotJobTask entity = RobotJobTaskConvert.INSTANCE.convert(reqVO);
        entity.setStatus(RobotJobTaskStatus.INITIALIZING.getValue())
                .setAdId(userUtil.getId());
        baseMapper.insert(entity);
        schedulerManager.addJob(entity.getId(), TaskJobHandler.NAME, null, entity.getCron(), 0, 0);
        // 改为开启中状态
        baseMapper.updateById(entity.setStatus(OPENING.getValue()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) throws SchedulerException {
        checkJobExists(id);
        baseMapper.deleteById(id);
        // 删除 quartz 中的 job
        schedulerManager.deleteJob(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(RobotJobTaskUpdateReqVO reqVO) throws SchedulerException {
        RobotJobTask oldEntity = checkJobExists(reqVO.getId());
        checkCron(reqVO.getCron());
        checkNameUnique(reqVO.getId(), reqVO.getName());
        RobotJobTask entity = RobotJobTaskConvert.INSTANCE.convert(reqVO);
        baseMapper.updateById(entity);
        // 任务不在暂停状态时才可更新 quartz 任务,不然会导致暂停的任务启动
        if (!PAUSING.getValue().equals(oldEntity.getStatus())) {
            schedulerManager.updateJob(entity.getId(), TaskJobHandler.NAME, null, entity.getCron(), 0, 0);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Integer status) throws SchedulerException {
        if (!CollUtil.safeContains(Arrays.asList(OPENING.getValue(), PAUSING.getValue()), status)) {
            throw new ServiceException("非法的状态值 :" + status);
        }
        RobotJobTask old = checkJobExists(id);
        if (old.getStatus().equals(status)) {
            throw new ServiceException("已处于该状态,无需修改");
        }
        baseMapper.updateById(new RobotJobTask().setId(id).setStatus(status));

        // 修改 quartz 中任务的状态
        if (OPENING.getValue().equals(status)) {
            // 开启
            schedulerManager.resumeJob(id);
            schedulerManager.updateJob(old.getId(), TaskJobHandler.NAME, null, old.getCron(), 0, 0);
        } else {
            // 暂停 (上方已限定 status 为 开启 和 关闭 两种值 所以可以用 else)
            schedulerManager.pauseJob(id);
        }
    }

    @Override
    public void triggerJobTask(Long jobId) throws SchedulerException {
        checkJobExists(jobId);
        schedulerManager.triggerJob(jobId,TaskJobHandler.NAME,null);
    }

    private void checkNameUnique(Long id, String name) {
        RobotJobTask t = baseMapper.selectOne(new LambdaQueryWrapperX<RobotJobTask>()
                .eq(RobotJobTask::getName, name)
                .eq(RobotJobTask::getAdId, userUtil.getId())
                .neIfPresent(RobotJobTask::getId, id));
        if (t != null) {
            throw new ServiceException("名称不可重复");
        }
    }

    private void checkCron(String cron) {
        if (!CronUtils.isValid(cron)) {
            throw new ServiceException("cron 表达式不正确");
        }
    }

    private RobotJobTask checkJobExists(Long id) {
        RobotJobTask entity = baseMapper.selectById(id);
        if (entity == null) {
            throw new ServiceException("任务不存在");
        }
        return entity;
    }

}




